home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ShareWare OnLine 2
/
ShareWare OnLine Volume 2 (CMS Software)(1993).iso
/
os2
/
remin301.zip
/
REMIN300.ZIP
/
EXPR.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-11-10
|
37KB
|
1,213 lines
/***************************************************************/
/* */
/* EXPR.C */
/* */
/* This file contains routines to parse and evaluate */
/* expressions. */
/* */
/* Copyright 1991 by David F. Skoll. */
/* */
/***************************************************************/
/* If we're using Turbo C, turn off annoying warning messages! */
#ifdef __TURBOC__
#pragma warn -pia
#endif
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include "config.h"
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_MALLOC_H
#include <malloc.h>
#endif
#include "err.h"
#include "types.h"
#include "expr.h"
#include "protos.h"
#include "globals.h"
#define ISID(c) (isalnum(c) || (c) == '_')
#define EQ 0
#define GT 1
#define LT 2
#define GE 3
#define LE 4
#define NE 5
static char ExprBuf[TOKSIZE+1];
static char CoerceBuf[TOKSIZE+1];
extern int NumFuncs;
#ifdef HAVE_PROTOS
PRIVATE int Multiply(void), Divide(void), Mod(void), Add(void),
Subtract(void), GreaterThan(void), LessThan(void),
EqualTo(void), NotEqual(void), LessOrEqual(void),
GreaterOrEqual(void), LogAND(void), LogOR(void),
UnMinus(void), LogNot(void),
Compare(int);
PRIVATE Operator *FindFunc(char *name, Operator where[], int num);
#else
PRIVATE int Multiply(), Divide(), Mod(), Add(),
Subtract(), GreaterThan(), LessThan(),
EqualTo(), NotEqual(), LessOrEqual(),
GreaterOrEqual(), LogAND(), LogOR(),
UnMinus(), LogNot(), Compare();
PRIVATE Operator *FindFunc();
#endif
PRIVATE int MakeValue ARGS ((char *s, Value *v, Var *locals));
PRIVATE int PushOpStack ARGS ((Operator *op));
PRIVATE int PopOpStack ARGS ((Operator *op));
/* Binary operators - all left-associative */
/* Make SURE they are sorted lexically... this may die on an EBCDIC
system... */
Operator BinOp[] = {
{ "!=", 15, BIN_OP, NotEqual },
{ "%", 20, BIN_OP, Mod },
{ "&&", 14, BIN_OP, LogAND },
{ "*", 20, BIN_OP, Multiply },
{ "+", 18, BIN_OP, Add },
{ "-", 18, BIN_OP, Subtract },
{ "/", 20, BIN_OP, Divide },
{ "<", 16, BIN_OP, LessThan },
{ "<=", 16, BIN_OP, LessOrEqual },
{ "==", 15, BIN_OP, EqualTo },
{ ">", 16, BIN_OP, GreaterThan },
{ ">=", 16, BIN_OP, GreaterOrEqual },
{ "||", 12, BIN_OP, LogOR },
};
#define NUM_BIN_OPS (sizeof(BinOp) / sizeof(Operator))
/* These ones must be sorted too. */
Operator UnOp[] = {
{ "!", 22, UN_OP, LogNot },
{ "-", 22, UN_OP, UnMinus },
};
#define NUM_UN_OPS (sizeof(UnOp) / sizeof(Operator))
/* Functions have the same definitions as operators, except the prec field
is used to indicate how many arguments are needed. */
extern Operator Func[];
Operator OpStack[OP_STACK_SIZE];
Value ValStack[VAL_STACK_SIZE];
int OpStackPtr, ValStackPtr;
/***************************************************************/
/* */
/* DebugPerform */
/* */
/* Execute an operator or function with debugging. */
/* */
/***************************************************************/
#ifdef HAVE_PROTOS
PRIVATE int DebugPerform(Operator *op)
#else
static int DebugPerform(op)
Operator *op;
#endif
{
int r;
if (op->type == UN_OP) {
fprintf(ErrFp, "%s ", op->name);
PrintValue(&ValStack[ValStackPtr-1], ErrFp);
} else { /* Must be binary operator */
PrintValue(&ValStack[ValStackPtr-2], ErrFp);
fprintf(ErrFp, " %s ", op->name);
PrintValue(&ValStack[ValStackPtr-1], ErrFp);
}
r = (op->func)();
fprintf(ErrFp, " => ");
if (!r) {
PrintValue(&ValStack[ValStackPtr-1], ErrFp);
putc('\n', ErrFp);
} else {
fprintf(ErrFp, "%s\n", ErrMsg[r]);
}
return r;
}
/***************************************************************/
/* */
/* CleanStack */
/* */
/* Clean the stack after an error occurs. */
/* */
/***************************************************************/
#ifdef HAVE_PROTOS
PRIVATE void CleanStack(void)
#else
static void CleanStack()
#endif
{
int i;
for (i=0; i<ValStackPtr; i++) DestroyValue(&ValStack[i]);
ValStackPtr = 0;
}
/***************************************************************/
/* */
/* PeekChar - peek ahead to next char. */
/* */
/***************************************************************/
#ifdef HAVE_PROTOS
PRIVATE char PeekChar(char **s)
#else
static char PeekChar(s)
char **s;
#endif
{
char *t = *s;
while (*t && isspace(*t)) t++;
return *t;
}
/***************************************************************/
/* */
/* ParseExprToken */
/* */
/* Read a token. */
/* */
/***************************************************************/
#ifdef HAVE_PROTOS
PRIVATE int ParseExprToken(char *out, char **in)
#else
static int ParseExprToken(out, in)
char *out;
char **in;
#endif
{
char c;
*out = 0;
/* Skip white space */
while (**in && isspace(**in)) (*in)++;
if (!**in) return OK;
*out++ = c = *(*in)++;
*out = 0;
switch(c) {
case COMMA:
case END_OF_EXPR:
case '+':
case '-':
case '*':
case '/':
case '(':
case ')':
case '%': return OK;
case '&':
case '|':
case '=': if (**in == c) {
*out++ = c;
*out = 0;
(*in)++;
}
return OK;
case '!':
case '>':
case '<': if (**in == '=') {
*out++ = '=';
*out = 0;
(*in)++;
}
return OK;
}
/* Handle the parsing of quoted strings */
if (c == '\"') {
while (**in) if ((c = *out++ = *(*in)++) == '\"') break;
*out = 0;
if (c == '\"') return OK ; else return E_MISS_QUOTE;
}
if (!ISID(c)) return E_ILLEGAL_CHAR;
/* Parse a constant, variable name or function */
while (ISID(**in) || **in == ':') *out++ = *(*in)++;
/* Chew up any remaining white space */
while (**in && isspace(**in)) (*in)++;
/* Peek ahead - is it '('? Then we have a function call */
if (**in == '(') *out++ = *(*in)++;
*out = 0;
return OK;
}
/***************************************************************/
/* */
/* EvalExpr */
/* Evaluate an expression. Return 0 if OK, non-zero if error */
/* Put the result into value pointed to by v. */
/* */
/***************************************************************/
#ifdef HaveProtos
PUBLIC int EvalExpr(char **e, Value *v)
#else
int EvalExpr(e, v)
char **e;
Value *v;
#endif
{
int r;
OpStackPtr = 0;
ValStackPtr = 0;
r = Evaluate(e, NULL);
/* Put last character parsed back onto input stream */
if (*ExprBuf) (*e)--;
if (r) {
CleanStack();
return r;
}
r = CopyValue(v, ValStack);
DestroyValue(ValStack);
return r;
}
/* Evaluate - do the actual work of evaluation. */
#ifdef HAVE_PROTOS
PUBLIC int Evaluate(char **s, Var *locals)
#else
int Evaluate(s, locals)
char **s;
Var *locals;
#endif
{
int OpBase, ValBase;
int r;
Operator *f;
int args; /* Number of function arguments */
Operator op, op2;
Value va;
char *ufname;
OpBase = OpStackPtr;
ValBase = ValStackPtr;
while(1) {
/* Looking for a value. Accept: value, unary op, func. call or left paren */
r = ParseExprToken(ExprBuf, s);
if (r) return r;
if (!*ExprBuf) return E_EOLN;
if (*ExprBuf == '(') { /* Parenthesized expression */
r = Evaluate(s, locals); /* Leaves the last parsed token in ExprBuf */
if (r) return r;
if (*ExprBuf != ')') return E_MISS_RIGHT_PAREN;
} else if (*ExprBuf == '+') continue; /* Ignore unary + */
else if (*(ExprBuf + strlen(ExprBuf) -1) == '(') { /* Function Call */
*(ExprBuf + strlen(ExprBuf) - 1) = 0;
f = FindFunc(ExprBuf, Func, NumFuncs);
if (!f) {
ufname = StrDup(ExprBuf);
if (!ufname) return E_NO_MEM;
}
args = 0;
if (PeekChar(s) == ')') { /* Function has no arguments */
if (f) r = CallFunc(f, 0);
else {
r = CallUserFunc(ufname, 0);
free(ufname);
}
if (r) return r;
(void) ParseExprToken(ExprBuf, s); /* Guaranteed to be right paren. */
} else { /* Function has some arguments */
while(1) {
args++;
r = Evaluate(s, locals);
if (r) return r;
if (*ExprBuf == ')') break;
else if (*ExprBuf != ',') return E_ILLEGAL_CHAR;
}
if (f) r = CallFunc(f, args);
else {
r = CallUserFunc(ufname, args);
free(ufname);
}
if (r) return r;
}
} else { /* Unary operator */
f = FindFunc(ExprBuf, UnOp, NUM_UN_OPS);
if (f) {
r = PushOpStack(f);
if (r) return r;
continue; /* Still looking for an atomic vlue */
} else if (!ISID(*ExprBuf) && *ExprBuf != '"') {
return E_ILLEGAL_CHAR;
} else { /* Must be a literal value */
r = MakeValue(ExprBuf, &va, locals);
if (r) return r;
r = PushValStack(&va);
if (r) return r;
}
}
/* OK, we've got a literal value; now, we're looking for the end of the
expression, or a binary operator. */
r = ParseExprToken(ExprBuf, s);
if (r) return r;
if (*ExprBuf == 0 || *ExprBuf == ',' || *ExprBuf == ']' || *ExprBuf == ')') {
/* We've hit the end of the expression. Pop off and evaluate until
OpStackPtr = OpBase and ValStackPtr = ValBase+1 */
while (OpStackPtr > OpBase) {
r = PopOpStack(&op);
if (r) return r;
if (DebugFlag & DB_PRTEXPR)
r=DebugPerform(&op);
else
r=(op.func)();
if (r) {
Eprint("Operator '%s' %s", op.name, ErrMsg[r]);
return r;
}
}
if (ValStackPtr != ValBase+1) return E_STACK_ERR; else return OK;
}
/* Must be a binary operator */
f = FindFunc(ExprBuf, BinOp, NUM_BIN_OPS);
if (!f) return E_EXPECTING_BINOP;
/* While operators of higher or equal precedence are on the stack,
pop them off and evaluate */
while (OpStackPtr > OpBase && OpStack[OpStackPtr-1].prec >= f->prec) {
r = PopOpStack(&op2);
if (r) return r;
if (DebugFlag & DB_PRTEXPR)
r=DebugPerform(&op2);
else
r=(op2.func)();
if (r) {
Eprint("Operator '%s' %s", op2.name, ErrMsg[r]);
return r;
}
}
r = PushOpStack(f);
if (r) return r;
}
}
/***************************************************************/
/* */
/* MakeValue */
/* Generate a literal value. It's either a string, a number */
/* or the value of a symbol. */
/* */
/***************************************************************/
#ifdef HAVE_PROTOS
PRIVATE int MakeValue(char *s, Value *v, Var *locals)
#else
static int MakeValue(s, v, locals)
char *s;
Value *v;
Var *locals;
#endif
{
int len;
int h, m, r;
if (*s == '\"') { /* It's a literal string */
len = strlen(s)-1;
v->type = STR_TYPE;
v->v.str = (char *) malloc(len);
if (! v->v.str) {
v->type = ERR_TYPE;
return E_NO_MEM;
}
strncpy(v->v.str, s+1, len-1);
*(v->v.str+len-1) = 0;
return OK;
} else if (isdigit(*s)) { /* It's a number - use len to hold it.*/
len = 0;
while (*s && isdigit(*s)) {
len *= 10;
len += (*s++ - '0');
}
if (*s == ':') { /* Must be a literal time */
s++;
if (!isdigit(*s)) return E_BAD_TIME;
h = len;
m = 0;
while (isdigit(*s)) {
m *= 10;
m += *s - '0';
s++;
}
if (*s || h>23 || m>59) return E_BAD_TIME;
v->type = TIM_TYPE;
v->v.val = h*60 + m;
return OK;
}
/* Not a time - must be a number */
if (*s) return E_BAD_NUMBER;
v->type = INT_TYPE;
v->v.val = len;
return OK;
} else /* Must be a symbol */
if (DebugFlag & DB_PRTEXPR)
fprintf(ErrFp, "%s => ", s);
r = GetVarValue(s, v, locals);
if (! (DebugFlag & DB_PRTEXPR)) return r;
if (r == OK) {
PrintValue(v, ErrFp);
putc('\n', ErrFp);
}
return r;
}
/***************************************************************/
/* */
/* PushOpStack */
/* */
/* Push an operator onto the operator stack. */
/* */
/***************************************************************/
#ifdef HAVE_PROTOS
PRIVATE int PushOpStack(Operator *op)
#else
static int PushOpStack(op)
Operator *op;
#endif
{
if (OpStackPtr >= OP_STACK_SIZE)
return E_OP_STK_OVER;
else {
OpStack[OpStackPtr++] = *op;
return OK;
}
}
/***************************************************************/
/* */
/* PushValStack */
/* */
/* Push a value onto the value stack. */
/* */
/***************************************************************/
#ifdef HAVE_PROTOS
PUBLIC int PushValStack(Value *val)
#else
int PushValStack(val)
Value *val;
#endif
{
if (ValStackPtr >= VAL_STACK_SIZE)
return E_VA_STK_OVER;
else {
ValStack[ValStackPtr++] = *val;
return OK;
}
}
/***************************************************************/
/* */
/* PopOpStack */
/* */
/* Pop an operator from the operator stack. */
/* */
/***************************************************************/
#ifdef HAVE_PROTOS
PRIVATE int PopOpStack(Operator *op)
#else
static int PopOpStack(op)
Operator *op;
#endif
{
if (OpStackPtr <= 0)
return E_OP_STK_UNDER;
else {
*op = OpStack[--OpStackPtr];
return OK;
}
}
/***************************************************************/
/* */
/* PopValStack */
/* */
/* Pop a value onto the value stack. */
/* */
/***************************************************************/
#ifdef HAVE_PROTOS
PUBLIC int PopValStack(Value *val)
#else
int PopValStack(val)
Value *val;
#endif
{
if (ValStackPtr <= 0)
return E_VA_STK_UNDER;
else {
*val = ValStack[--ValStackPtr];
return OK;
}
}
/***************************************************************/
/* */
/* DoCoerce - actually coerce a value to the specified type. */
/* */
/***************************************************************/
#ifdef HAVE_PROTOS
PUBLIC int DoCoerce(char type, Value *v)
#else
int DoCoerce(type, v)
char type;
Value *v;
#endif
{
int h, d, m, y, i;
char *s;
/* Do nothing if value is already the right type */
if (type == v->type) return OK;
switch(type) {
case STR_TYPE:
switch(v->type) {
case INT_TYPE: sprintf(CoerceBuf, "%d", v->v.val); break;
case TIM_TYPE: sprintf(CoerceBuf, "%02d:%02d", v->v.val / 60, v->v.val % 60);
break;
case DATE_TYPE: FromJulian(v->v.val, &y, &m, &d);
sprintf(CoerceBuf, "%04d/%02d/%02d", y, m+1, d);
break;
default: return E_CANT_COERCE;
}
v->type = STR_TYPE;
v->v.str = StrDup(CoerceBuf);
if (!v->v.str) {
v->type = ERR_TYPE;
return E_NO_MEM;
}
return OK;
case INT_TYPE:
i = 0;
m = 1;
switch(v->type) {
case STR_TYPE:
s = v->v.str;
if (*s == '-') {
m = -1;
s++;
}
while(*s && isdigit(*s)) {
i *= 10;
i += (*s++) - '0';
}
if (*s) {
free (v->v.str);
v->type = ERR_TYPE;
return E_CANT_COERCE;
}
free(v->v.str);
v->type = INT_TYPE;
v->v.val = i * m;
return OK;
case DATE_TYPE:
case TIM_TYPE:
v->type = INT_TYPE;
return OK;
default: return E_CANT_COERCE;
}
case DATE_TYPE:
switch(v->type) {
case INT_TYPE:
if(v->v.val >= 0) {
v->type = DATE_TYPE;
return OK;
} else return E_2LOW;
case STR_TYPE:
y=0; m=0; d=0;
s = v->v.str;
if (!isdigit(*s)) return E_CANT_COERCE;
while (isdigit(*s)) {
y *= 10;
y += *s++ - '0';
}
if (*s++ != '/') return E_CANT_COERCE;
if (!isdigit(*s)) return E_CANT_COERCE;
while (isdigit(*s)) {
m *= 10;
m += *s++ - '0';
}
m--;
if (*s++ != '/') return E_CANT_COERCE;
if (!isdigit(*s)) return E_CANT_COERCE;
while (isdigit(*s)) {
d *= 10;
d += *s++ - '0';
}
if (*s || y < BASE || y > BASE+YR_RANGE ||
m>11 || d<1 || d>DaysInMonth(m, y)) return E_CANT_COERCE;
v->type = DATE_TYPE;
free(v->v.str);
v->v.val = Julian(y, m, d);
return OK;
default: return E_CANT_COERCE;
}
case TIM_TYPE:
switch(v->type) {
case INT_TYPE:
v->type = TIM_TYPE;
v->v.val %= 1440;
if (v->v.val < 0) v->v.val += 1440;
return OK;
case STR_TYPE:
h = 0;
m = 0;
s = v->v.str;
if (!isdigit(*s)) return E_CANT_COERCE;
while (isdigit(*s)) {
h *= 10;
h += *s++ - '0';
}
if (*s++ != ':') return E_CANT_COERCE;
if (!isdigit(*s)) return E_CANT_COERCE;
while (isdigit(*s)) {
m *= 10;
m += *s++ - '0';
}
if (*s || h>23 || m>59) return E_CANT_COERCE;
v->type = TIM_TYPE;
free(v->v.str);
v->v.val = h*60+m;
return OK;
default: return E_CANT_COERCE;
}
default: return E_CANT_COERCE;
}
}
/***************************************************************/
/* */
/* DestroyValue */
/* */
/* If value is of type string, deallocate string memory. */
/* */
/***************************************************************/
#ifdef HAVE_PROTOS
PUBLIC void DestroyValue(Value *v)
#else
void DestroyValue(v)
Value *v;
#endif
{
if (v->type == STR_TYPE && v->v.str) free(v->v.str);
v->type = ERR_TYPE;
}
/***************************************************************/
/* */
/* Add */
/* */
/* Perform addition. */
/* */
/***************************************************************/
#ifdef HAVE_PROTOS
PRIVATE int Add(void)
#else
static int Add()
#endif
{
Value v1, v2, v3;
int r;
if (r = PopValStack(&v2)) return r;
if (r = PopValStack(&v1)) {
DestroyValue(&v2);
return r;
}
/* If both are ints, just add 'em */
if (v2.type == INT_TYPE && v1.type == INT_TYPE) {
v2.v.val += v1.v.val;
return (PushValStack(&v2));
}
/* If it's a date plus an int, add 'em */
if ((v1.type == DATE_TYPE && v2.type == INT_TYPE) ||
(v1.type == INT_TYPE && v2.type == DATE_TYPE)) {
v1.v.val += v2.v.val;
v1.type = DATE_TYPE;
return PushValStack(&v1);
}
/* If it's a time plus an int, add 'em mod 1440 */
if ((v1.type == TIM_TYPE && v2.type == INT_TYPE) ||
(v1.type == INT_TYPE && v2.type == TIM_TYPE)) {
v1.v.val = (v1.v.val + v2.v.val) % 1440;
v1.type = TIM_TYPE;
return PushValStack(&v1);
}
/* If either is a string, coerce them both to strings and concatenate */
if (v1.type == STR_TYPE || v2.type == STR_TYPE) {
if (r = DoCoerce(STR_TYPE, &v1)) {
DestroyValue(&v1); DestroyValue(&v2);
return r;
}
if (r = DoCoerce(STR_TYPE, &v2)) {
DestroyValue(&v1); DestroyValue(&v2);
return r;
}
v3.type = STR_TYPE;
v3.v.str = (char *) malloc(strlen(v1.v.str) + strlen(v2.v.str) + 1);
if (!v3.v.str) {
DestroyValue(&v1); DestroyValue(&v2);
return E_NO_MEM;
}
strcpy(v3.v.str, v1.v.str);
strcat(v3.v.str, v2.v.str);
DestroyValue(&v1); DestroyValue(&v2);
return (PushValStack(&v3));
}
/* Don't handle other types yet */
return E_BAD_TYPE;
}
/***************************************************************/
/* */
/* Subtract */
/* */
/* Perform subtraction. */
/* */
/***************************************************************/
#ifdef HAVE_PROTOS
PRIVATE int Subtract(void)
#else
static int Subtract()
#endif
{
Value v1, v2;
int r;
if (r = PopValStack(&v2)) return r;
if (r = PopValStack(&v1)) {
DestroyValue(&v2);
return r;
}
/* If they're both INTs, do subtraction */
if (v1.type == INT_TYPE && v2.type == INT_TYPE) {
v1.v.val -= v2.v.val;
return PushValStack(&v1);
}
/* If it's a date minus an int, do subtraction, checking for underflow */
if (v1.type == DATE_TYPE && v2.type == INT_TYPE) {
v1.v.val -= v2.v.val;
if (v1.v.val < 0) return E_DATE_OVER;
return PushValStack(&v1);
}
/* If it's a time minus an int, do subtraction mod 1440 */
if (v1.type == TIM_TYPE && v2.type == INT_TYPE) {
v1.v.val = (v1.v.val - v2.v.val) % 1440;
return PushValStack(&v1);
}
/* If it's a time minus a time or a date minus a date, do it */
if ((v1.type == TIM_TYPE && v2.type == TIM_TYPE) ||
(v1.type == DATE_TYPE && v2.type == DATE_TYPE)) {
v1.v.val -= v2.v.val;
v1.type = INT_TYPE;
return PushValStack(&v1);
}
/* Must be types illegal for subtraction */
DestroyValue(&v1); DestroyValue(&v2);
return E_BAD_TYPE;
}
/***************************************************************/
/* */
/* Multiply */
/* */
/* Perform multiplication. */
/* */
/***************************************************************/
#ifdef HAVE_PROTOS
PRIVATE int Multiply(void)
#else
static int Multiply()
#endif
{
Value v1, v2;
int r;
if (r = PopValStack(&v2)) return r;
if (r = PopValStack(&v1)) {
DestroyValue(&v2);
return r;
}
if (v1.type == INT_TYPE && v2.type == INT_TYPE) {
v1.v.val *= v2.v.val;
return PushValStack(&v1);
}
DestroyValue(&v1); DestroyValue(&v2);
return E_BAD_TYPE;
}
/***************************************************************/
/* */
/* Divide */
/* */
/* Perform division. */
/* */
/***************************************************************/
#ifdef HAVE_PROTOS
PRIVATE int Divide(void)
#else
static int Divide()
#endif
{
Value v1, v2;
int r;
if (r = PopValStack(&v2)) return r;
if (r = PopValStack(&v1)) {
DestroyValue(&v2);
return r;
}
if (v1.type == INT_TYPE && v2.type == INT_TYPE) {
if (v2.v.val == 0) return E_DIV_ZERO;
v1.v.val /= v2.v.val;
return PushValStack(&v1);
}
DestroyValue(&v1); DestroyValue(&v2);
return E_BAD_TYPE;
}
/***************************************************************/
/* */
/* Mod */
/* */
/* Perform modulus function. */
/* */
/***************************************************************/
#ifdef HAVE_PROTOS
PRIVATE int Mod(void)
#else
static int Mod()
#endif
{
Value v1, v2;
int r;
if (r = PopValStack(&v2)) return r;
if (r = PopValStack(&v1)) {
DestroyValue(&v2);
return r;
}
if (v1.type == INT_TYPE && v2.type == INT_TYPE) {
if (v2.v.val == 0) return E_DIV_ZERO;
v1.v.val %= v2.v.val;
return PushValStack(&v1);
}
DestroyValue(&v1); DestroyValue(&v2);
return E_BAD_TYPE;
}
/***************************************************************/
/* */
/* GreaterThan, LessThan, EqualTo, NotEqual, LessOrEqual, */
/* GreaterOrEqual */
/* */
/* All the comparison functions. */
/* */
/***************************************************************/
#ifdef HAVE_PROTOS
PRIVATE int GreaterThan(void) {return Compare(GT);}
PRIVATE int LessThan(void) {return Compare(LT);}
PRIVATE int EqualTo(void) {return Compare(EQ);}
PRIVATE int NotEqual(void) {return Compare(NE);}
PRIVATE int LessOrEqual(void) {return Compare(LE);}
PRIVATE int GreaterOrEqual(void) {return Compare(GE);}
#else
static int GreaterThan() {return Compare(GT);}
static int LessThan() {return Compare(LT);}
static int EqualTo() {return Compare(EQ);}
static int NotEqual() {return Compare(NE);}
static int LessOrEqual() {return Compare(LE);}
static int GreaterOrEqual() {return Compare(GE);}
#endif
/***************************************************************/
/* */
/* Compare */
/* Do the actual work of comparison. */
/* */
/***************************************************************/
#ifdef HAVE_PROTOS
PRIVATE int Compare(int how)
#else
static int Compare(how)
int how;
#endif
{
Value v1, v2, v3;
int r;
if (r = PopValStack(&v2)) return r;
if (r = PopValStack(&v1)) {
DestroyValue(&v2);
return r;
}
/* Special case for EQ and NE */
v3.type = INT_TYPE;
if (v1.type != v2.type) {
DestroyValue(&v1); DestroyValue(&v2);
if (how == EQ) {
v3.v.val = 0;
return PushValStack(&v3);
} else if (how == NE) {
v3.v.val = 1;
return PushValStack(&v3);
} else return E_BAD_TYPE;
}
if (v1.type == STR_TYPE) {
switch(how) {
case EQ: v3.v.val = (strcmp(v1.v.str, v2.v.str) == 0); break;
case NE: v3.v.val = (strcmp(v1.v.str, v2.v.str) != 0); break;
case LT: v3.v.val = (strcmp(v1.v.str, v2.v.str) < 0); break;
case GT: v3.v.val = (strcmp(v1.v.str, v2.v.str) > 0); break;
case LE: v3.v.val = (strcmp(v1.v.str, v2.v.str) <= 0); break;
case GE: v3.v.val = (strcmp(v1.v.str, v2.v.str) >= 0); break;
}
} else {
switch(how) {
case EQ: v3.v.val = (v1.v.val == v2.v.val); break;
case NE: v3.v.val = (v1.v.val != v2.v.val); break;
case LT: v3.v.val = (v1.v.val < v2.v.val); break;
case GT: v3.v.val = (v1.v.val > v2.v.val); break;
case LE: v3.v.val = (v1.v.val <= v2.v.val); break;
case GE: v3.v.val = (v1.v.val >= v2.v.val); break;
}
}
DestroyValue(&v1); DestroyValue(&v2);
return PushValStack(&v3);
}
/***************************************************************/
/* */
/* LogOR */
/* */
/* Do logical OR */
/* */
/***************************************************************/
#ifdef HAVE_PROTOS
PRIVATE int LogOR(void)
#else
static int LogOR()
#endif
{
Value v1, v2;
int r;
if (r = PopValStack(&v2)) return r;
if (r = PopValStack(&v1)) {
DestroyValue(&v2);
return r;
}
if (v1.type == INT_TYPE && v2.type == INT_TYPE) {
v1.v.val = (v1.v.val || v2.v.val) ? 1 : 0;
return PushValStack(&v1);
}
DestroyValue(&v1); DestroyValue(&v2);
return E_BAD_TYPE;
}
/***************************************************************/
/* */
/* LogAND */
/* */
/* Do logical AND */
/* */
/***************************************************************/
#ifdef HAVE_PROTOS
PRIVATE int LogAND(void)
#else
static int LogAND()
#endif
{
Value v1, v2;
int r;
if (r = PopValStack(&v2)) return r;
if (r = PopValStack(&v1)) {
DestroyValue(&v2);
return r;
}
if (v1.type == INT_TYPE && v2.type == INT_TYPE) {
v1.v.val = (v1.v.val && v2.v.val) ? 1 : 0;
return PushValStack(&v1);
}
DestroyValue(&v1); DestroyValue(&v2);
return E_BAD_TYPE;
}
/***************************************************************/
/* */
/* UnMinus */
/* */
/* Unary Minus */
/* */
/***************************************************************/
#ifdef HAVE_PROTOS
PRIVATE int UnMinus(void)
#else
static int UnMinus()
#endif
{
Value *v = &ValStack[ValStackPtr-1];
if (v->type != INT_TYPE) return E_BAD_TYPE;
v->v.val = -v->v.val;
return OK;
}
/***************************************************************/
/* */
/* LogNot */
/* */
/* Logical NOT */
/* */
/***************************************************************/
#ifdef HAVE_PROTOS
PRIVATE int LogNot(void)
#else
static int LogNot()
#endif
{
Value *v = &ValStack[ValStackPtr-1];
if (v->type != INT_TYPE) return E_BAD_TYPE;
if (v->v.val) v->v.val = 0; else v->v.val = 1;
return OK;
}
/***************************************************************/
/* */
/* FindFunc */
/* */
/* Find a function. */
/* */
/***************************************************************/
#ifdef HAVE_PROTOS
PRIVATE Operator *FindFunc(char *name, Operator where[], int num)
#else
static Operator *FindFunc(name, where, num)
char *name;
Operator where[];
int num;
#endif
{
int top=num-1, bot=0;
int mid, r;
while (top >= bot) {
mid = (top + bot) / 2;
r = StrCmpi(name, where[mid].name);
if (!r) return &where[mid];
else if (r > 0) bot = mid+1;
else top = mid-1;
}
return NULL;
}
/***************************************************************/
/* */
/* PrintValue */
/* */
/* Print a value to stdout for debugging purposes. */
/* */
/***************************************************************/
#ifdef HAVE_PROTOS
PUBLIC void PrintValue (Value *v, FILE *fp)
#else
void PrintValue(v, fp)
Value *v;
FILE *fp;
#endif
{
int y, m, d;
char *s;
if (v->type == STR_TYPE) {
s=v->v.str;
putc('"', fp);
for (y=0; y<MAX_PRT_LEN && *s; y++) putc(*s++, fp);
putc('"',fp);
if (*s) fprintf(fp, "...");
}
else if (v->type == INT_TYPE) fprintf(fp, "%d", v->v.val);
else if (v->type == TIM_TYPE) fprintf(fp, "%02d:%02d", v->v.val / 60, v->v.val % 60);
else if (v->type == DATE_TYPE) {
FromJulian(v->v.val, &y, &m, &d);
fprintf(fp, "%04d/%02d/%02d", y, m+1, d);
}
else fprintf(fp, "ERR");
}
/***************************************************************/
/* */
/* CopyValue */
/* */
/* Copy a value. */
/* */
/***************************************************************/
#ifdef HAVE_PROTOS
PUBLIC int CopyValue(Value *dest, const Value *src)
#else
int CopyValue(dest, src)
Value *dest, *src;
#endif
{
dest->type = src->type;
if (src->type == STR_TYPE) {
dest->v.str = StrDup(src->v.str);
if (!dest->v.str) {
dest->type = ERR_TYPE;
return E_NO_MEM;
}
return OK;
} else {
dest->v.val = src->v.val;
return OK;
}
}